#include "../include/thread_pool.h"
#include "../include/server.h"

int exitPipe[2]; // 父进程向子进程发送退出信息的管道

void sigFunc(int sigNum){
    //信号处理函数
    printf("SIGUSR1 is coming!\n");
    write(exitPipe[1], &sigNum, 4);
}

int main(int argc,char*argv[])
{
    // ./ ip port threadNum
    ARGS_CHECK(argc, 4);
    pipe(exitPipe);

    if(fork()){
        //主进程用来监听退出信号，并把退出信号发给管理线程池的子进程，实现线程池的退出
        close(exitPipe[0]);//关闭读端
        signal(SIGUSR1, sigFunc);
        wait(NULL);//等待子进程关闭
        printf("i quite!\n");
        exit(0);
    }

    // ======子进程管理线程池======
    close(exitPipe[1]);  //子线程关闭写端
    int threadNum = atoi(argv[3]);
    // 1、启动线程池
    ThreadPool_t pool;
    threadPoolInit(&pool, threadNum); // 初始化线程池
    threadPoolStart(&pool); //启动线程池

    // 2、创建socket监听客户端请求
    int sockFd;
    tcpInit(&sockFd, argv[1], argv[2]);

    // 3、创建epoll
    int epfd = epoll_create(1);

    // 把sockFd和exitPipe加入epfd中
    epollAddNewFd(epfd, sockFd);
    int ret = epollAddNewFd(epfd, exitPipe[0]);
    if(-1 == ret){
        printf("epollAddNewFd\n");
    }
    struct epoll_event evs[2];

    int sockNewFd = 0;//和客户端建立新连接的socket
    int readyNum = 0;
    char buf[128] = {0};
    int ownerID = 1;
    int curDirID = 0;
    int lsRet = 0;

    //切换到服务器存放文件的目录
    chdir("/home/albert/netdisk_file");

    //循环，接收连接请求，调用线程池中的线程完成向客户端发送文件的任务
    while(1){
        readyNum = epoll_wait(epfd, evs, 2, -1);
        for(int i = 0; i < readyNum; ++i){
            if(evs[i].data.fd == sockFd){
                //有来自客户端的连接请求
                sockNewFd = accept(sockFd, NULL, NULL);
                ERROR_CHECK(sockNewFd, -1, "accept");
                printf("client connect!\n");

                //有新的连接请求，先登录
                ownerID = serverLogin(sockNewFd);
                if(-1 == ownerID){
                    printf("client login failed!\n");
                    break;
                }
                //其他用户登录，切回根目录
                curDirID = 0;
                lsRet = 0;

                updatePwd(ownerID, "/");

                //插入登录日志
                insertLog(ownerID, "login");

                epollAddNewFd(epfd, sockNewFd);

                /* //创建一个新的任务结点，并将其加入到任务队列中 */
                /* pTaskNode_t pNew = (pTaskNode_t)calloc(1, sizeof(TaskNode_t)); */
                /* pNew->clientFd = sockNewFd; */
                /* pNew->pNext = NULL; */
                /* pthread_mutex_lock(&pool.tQue.mutex); */
                /* taskQueInsert(&pool.tQue, pNew); */
                /* //任务队列中有了任务，通知线程池中在wait的子线程 */
                /* pthread_cond_signal(&pool.tQue.cond1); */
                /* pthread_mutex_unlock(&pool.tQue.mutex);//解锁 */
            }
            if(evs[i].data.fd == sockNewFd){
                //========客户端发来命令=========
                int cmdtype = 0;
                char cmd[20] = {0};
                char arg[64] = {0};

                memset(buf, 0, sizeof(buf));
                ret = recv(sockNewFd, buf, 128, 0);
                printf("curDirID = %d,  cmd = %s\n", curDirID, buf);

                if(ret == 0){
                    printf("client exit!\n");
                    //插入登出记录
                    insertLog(ownerID, "logout");
                    //把sockNewFd从epfd中删除
                    epollDelFd(epfd, sockNewFd);
                    continue;
                    /* exit(0); */
                }

                cmdtype = CMDtype(buf, cmd, arg);
                /* printf("arg = %s\n", arg); */
                memset(buf, 0, sizeof(buf));
                sprintf(buf, "%s %s", cmd, arg);
                //把指令插入日志中
                insertLog(ownerID, buf);

                switch (cmdtype){
                case 1:
                    //cd指令
                    /* printf("curDirID = %d\n", curDirID); */
                    serverCd(sockNewFd, &curDirID, ownerID, arg);
                    /* curDirID = mycd3(sockNewFd, arg, ownerID, curDirID); */
                    /* printf("curDirID = %d\n", curDirID); */
                    break;
                case 2:
                    //ls指令
                    lsRet = myls3(sockNewFd, ownerID, curDirID);
                    /* printf("lsRet = %d\n", lsRet); */
                    break;
                case 3:
                    //pwd指令
                    /* printf("curDirID = %d\n", curDirID); */
                    serverPwd(sockNewFd, curDirID, ownerID);
                    break;
                case 4:
                    //gets指令,客户端要上传文件了
                    serverGets(sockNewFd, curDirID, ownerID);
                    break;
                case 5:
                    //puts指令，客户端请求下载文件
                    serverPuts(sockNewFd, arg, curDirID, ownerID);
                    break;
                case 6:
                    //rm指令，删除服务器上的文件
                    serverRm(sockNewFd, arg, curDirID, ownerID);
                    break;
                case 7:
                    //mkdir指令，新建文件夹
                    serverMkdir(sockNewFd, arg, curDirID, ownerID);
                    break;
                }
            }
            if(evs[i].data.fd == exitPipe[0]){
                //如果是父进程发来了退出信号，有序退出
                //加锁，修改队列标志位，通知全部子线程
                pthread_mutex_lock(&pool.tQue.mutex);
                pool.tQue.exitFlag = 1;
                pthread_cond_broadcast(&pool.tQue.cond1);
                pthread_mutex_unlock(&pool.tQue.mutex);

                //使用pthread_join等待全部子线程退出
                for(int j = 0; j < threadNum; ++j){
                    pthread_join(pool.pthid[j], NULL);
                }
                printf("child process exit!\n");
                exit(0);

            }
        }
    }

    return 0;
}

